package com.hengyue.system.service.impl;

import com.hengyue.common.util.PageUtil;
import com.hengyue.common.utils.StringUtils;
import com.hengyue.exception.ServiceException;
import com.hengyue.system.domain.criteria.SysUserCriteria;
import com.hengyue.system.domain.entity.SysRole;
import com.hengyue.system.domain.entity.SysUser;
import com.hengyue.system.mapstruct.mapper.SysUserVOMapper;
import com.hengyue.system.repository.SysRoleRepository;
import com.hengyue.system.repository.UserRepository;
import com.hengyue.system.service.ISysUserService;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@RequiredArgsConstructor
public class SysUserServiceImpl implements ISysUserService {


    private final UserRepository userRepository;
    private final SysUserVOMapper sysUserVOMapper;
    private final SysRoleRepository sysRoleRepository;

    public Set<Long> getRoleIds(@NotNull Long userId) {
        return userRepository.findRoleIdsByUserId(userId);
    }

    @Override
    public SysUser findUserByUserName(String userName) {
        return userRepository.findByName(userName);
    }

    @Override
    public void updateUserProfile(SysUser sysUser) {
        userRepository.save(sysUser);
    }

    @Override
    public boolean updateUserAvatar(String userName, String avatar) {
        return false;
    }

    @Override
    public void resetPwd(SysUser user) {

    }

    @Override
    public int resetUserPwd(String userName, String password) {
        return 0;
    }

    @Override
    public void deleteUserById(Long userId) {

    }

    @Override
    @Transactional
    public void deleteUserByIds(Long[] userIds) {
        // 1. 先解除用户-角色关联
        userRepository.deleteUserRoleRelations(userIds);
        // 2. 删除用户
        userRepository.deleteAllByIdInBatch(List.of(userIds));
    }

    @Override
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
        return null;
    }

    @Override
    public SysUser findUserById(@NotNull Long userId) {
        return userRepository.findById(userId)
                .orElseThrow(() -> new ServiceException("用户不存在"));
    }

    @Override
    public List<SysUser> selectUserList(SysUser user) {
        return null;
    }

    /**
     * @param criteria
     * @return
     */
    @Override
    public Page<SysUser> selectUserPageList(SysUserCriteria criteria, Pageable pageable) {
        return userRepository.findAll(getSpecification(criteria), pageable);
    }

    @Override
    public List<SysUser> selectAllocatedList(SysUser user) {
        return null;
    }


    @Override
    public Page<SysUser> selectUserListByRoleId(SysUserCriteria criteria) {
        Pageable pageable = PageUtil.getPageable();
        String roleId = criteria.getRoleId();
        Specification<SysUser> specification = getSpecification(criteria);
        specification = specification.and((root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.isNotBlank(criteria.getRoleId())) {
                // 使用 JOIN 操作关联 SysRole 实体
                Join<SysUser, SysRole> roleJoin = root.join("sysRoles", JoinType.INNER);
                // 转换 roleId 为 Long 类型，假设 SysRole 的 id 是 Long 类型
                predicates.add(criteriaBuilder.equal(roleJoin.get("id"), roleId));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        return userRepository.findAll(specification, pageable);
    }

    @Override
    @Transactional
    public Page<SysUser> selectUnallocatedList(SysUserCriteria criteria) {
        Pageable pageable = PageUtil.getPageable();
        String roleId = criteria.getRoleId();
        SysRole role = sysRoleRepository.findById(Long.valueOf(roleId)).orElseThrow(() -> new ServiceException("角色不存在"));
        Set<SysUser>  allocateUsers = role.getUsers();
        Specification<SysUser> specification = getSpecification(criteria);
        specification = specification.and((root, query, criteriaBuilder) -> {
            if (!allocateUsers.isEmpty()) {
                // 获取用户 ID 列表
                List<Long> userIds = allocateUsers.stream()
                        .map(SysUser::getId)
                        .toList();
                // 添加用户 ID 不在指定列表的条件
                return criteriaBuilder.not(root.get("id").in(userIds));
            }
            // 若 allocateUsers 为空，返回一个永远为 true 的 Predicate
            return criteriaBuilder.conjunction();
        });
        return userRepository.findAll(specification, pageable);
    }

    @Override
    public SysUser selectUserByUserName(String userName) {
        return null;
    }

    @Override
    public SysUser selectUserById(Long userId) {
        return userRepository.findById(userId).orElseThrow(() -> new ServiceException("用户不存在"));
    }

    @Override
    public String selectUserRoleGroup(String userName) {
        return null;
    }

    @Override
    public String selectUserPostGroup(String userName) {
        return null;
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public boolean isUserNameNotUnique(String userName, Long id) {
        Long userId = id == null ? -1L : id;
        return userRepository.existsByNameAndIdNot(userName, userId);
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param  phoneNumber 手机号码
     * @return 结果
     */
    @Override
    public boolean isPhoneNotUnique(String phoneNumber, Long id) {
        Long userId = id == null ? -1L : id;
        return userRepository.existsByPhoneNumberAndIdNot(phoneNumber, userId);
    }

    @Override
    public void checkUserAllowed(SysUser user) {

    }

    @Override
    public void checkUserDataScope(Long userId) {
    }

    @Override
    public void insertUser(SysUser user) {
        userRepository.save(user);
    }

    @Override
    public boolean registerUser(SysUser user) {
        return false;
    }

    @Override
    public void updateUser(SysUser user) {
        userRepository.save(user);
    }

    @Override
    @Transactional
    public void updateUserAuth(Long userId, Long[] roleIds) {
        SysUser sysUser = userRepository.findById(userId).orElseThrow(() -> new ServiceException("用户不存在"));
        // 直接创建要添加的角色集合
        Set<SysRole> newRoleSet = new HashSet<>();

        // 将 roleIds 数组转换为 List 后使用 forEach 方法
        List.of(roleIds).forEach(roleId -> {
            SysRole sysRole = new SysRole();
            sysRole.setId(roleId);
            newRoleSet.add(sysRole);
        });
        // 将新的角色集合赋值给用户
        sysUser.getSysRoles().addAll(newRoleSet);

        // 保存用户信息
        userRepository.save(sysUser);

    }

    @Override
    @Transactional
    public void deleteUserAuth(Long userId, Long[] roleIds) {
        SysUser sysUser = userRepository.findById(userId).orElseThrow(() -> new ServiceException("用户不存在"));
        // 直接创建要添加的角色集合
        Set<SysRole> newRoleSet = new HashSet<>();
        // 将 roleIds 数组转换为 List 后使用 forEach 方法
        List.of(roleIds).forEach(roleId -> {
            SysRole sysRole = new SysRole();
            sysRole.setId(roleId);
            newRoleSet.add(sysRole);
        });
        // 将新的角色集合赋值给用户
        sysUser.setSysRoles(newRoleSet);
        // 保存用户信息
        userRepository.save(sysUser);
    }

    @Override
    public void updateUserStatus(SysUser user) {
       SysUser sysUser = userRepository.findById(user.getId()).orElseThrow(() -> new ServiceException("用户不存在"));
       sysUser.setStatus(user.getStatus());
       userRepository.save(sysUser);
    }

    private Specification<SysUser> getSpecification(SysUserCriteria criteria) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("delFlag"), "0"));
            if (criteria.getId() != null) {
                predicates.add(cb.equal(root.get("id"), criteria.getId()));
            }
            if (StringUtils.isNotEmpty(criteria.getName())) {
                predicates.add(cb.like(root.get("name"), "%" + criteria.getName() + "%"));
            }
            if (criteria.getStatus() != null) {
                predicates.add(cb.equal(root.get("status"), criteria.getStatus()));
            }
            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

}
